﻿using System;
using Microsoft.FxCop.Sdk;

namespace Community.StaticAnalysis.Design.Rules
{
    /// <summary>
    /// The <see cref="MarkClassWithDataContract"/>
    /// class is used to identify classes that are not marked with the DataContract attribute 
    /// which define properties that are marked with the DataMember attribute.
    /// </summary>
    public class MarkClassWithDataContract : BaseIntrospectionRule
    {
        /// <summary>
        /// Initializes a new instance of the <see cref="MarkClassWithDataContract"/> class.
        /// </summary>
        public MarkClassWithDataContract()
            : base(
                typeof (MarkClassWithDataContract).Name,
                typeof (MarkClassWithDataContract).Namespace + Constants.RulesResourceNameSuffix,
                typeof (MarkClassWithDataContract).Assembly)
        {
        }

        /// <summary>
        /// Checks the specified type.
        /// </summary>
        /// <param name="type">The type.</param>
        /// <returns></returns>
        public override ProblemCollection Check(TypeNode type)
        {
            // Check if this class is marked with DataContract
            if (RulesHelper.NodeHasAttribute(type, Constants.DataContractFullName))
            {
                // This is a class that is marked with DataContract attribute
                return null;
            }

            DataMemberFound = false;

            Visit(type);

            // Check if the class is marked with DataContract
            if (DataMemberFound)
            {
                // This class is not a data contract by does have DataMember properties
                Problems.Add(new Problem(GetResolution(new Object[] { type.FullName })));
            }

            return Problems;
        }

        /// <summary>
        /// Visits the property.
        /// </summary>
        /// <param name="property">The property.</param>
        public override void VisitProperty(PropertyNode property)
        {
            // Check if a property has already been found
            if (DataMemberFound)
            {
                // We don't need to check any further properties
                return;
            }

            // Check if this property is marked with DataMember
            if (RulesHelper.NodeHasAttribute(property, Constants.DataMemberFullName))
            {
                // We have found a DataMember property
                DataMemberFound = true;
            }
        }

        /// <summary>
        /// Gets or sets a value indicating whether a data member property has been found.
        /// </summary>
        /// <value><c>true</c> if a data member property has been found; otherwise, <c>false</c>.</value>
        private Boolean DataMemberFound
        {
            get;
            set;
        }
    }
}